﻿/* ***********************************************
 * 
 * Author		:  飞无痕
 * Email		:  wsptr@sohu.com
 * DateTime		:  2012-1-30 17:22
 * Description	:  游戏手柄的封装类
 *
 * ***********************************************/

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;

namespace Walson.Multimedia
{
    /// <summary>
    /// 游戏手柄类
    /// </summary>
    public class Joystick : IDisposable
    {
        #region 结构
        /// <summary>
        /// 摇杆状态
        /// </summary>
        public struct JoystickState
        {
            /// <summary>
            /// 
            /// </summary>
            public int ID;
            /// <summary>
            /// 
            /// </summary>
            public JoystickAPI.JOYINFOEX JoystickInfo;
            /// <summary>
            /// 
            /// </summary>
            public List<byte> ButtonList;
            /// <summary>
            /// 
            /// </summary>
            public int ErrorCode;

            /// <summary>
            /// 转换为字符串
            /// </summary>
            /// <returns>转换结果</returns>
            public new string ToString()
            {
                StringBuilder strButtonList = new StringBuilder();
                if (ButtonList.Count > 0)
                    foreach (byte b in ButtonList)
                    {
                        strButtonList.Append(b.ToString() + " ");
                    }
                else
                    strButtonList.Append("无");
                return string.Format(
                     "ID:{0}\r\n"+
                     "按下的按键数量:{1}\t\t标志位:{2}\r\n" +
                     "POV:{3}\t\tSize:{4}\r\n" +
                     "Rpos:{5}\t\tUpos:{6}\t\tVpos:{7}\r\n" +
                     "Xpos:{8}\t\tYpos:{9}\t\tZpos:{10}\r\n" +
                     "按键列表：\r\n{11}",
                     ID,
                     JoystickInfo.dwButtonNumber,
                     JoystickInfo.dwFlags,
                     JoystickInfo.dwPOV,
                     JoystickInfo.dwSize,
                     JoystickInfo.dwRpos,
                     JoystickInfo.dwUpos,
                     JoystickInfo.dwVpos,
                     JoystickInfo.dwXpos,
                     JoystickInfo.dwYpos,
                     JoystickInfo.dwZpos,
                     strButtonList.ToString()
                     );
            }
        }

        #endregion
        /// <summary>
        /// 根据游戏手柄的Id实例化
        /// </summary>
        /// <param name="joystickId"></param>
        public Joystick(int joystickId)
        {
            this.Id = joystickId;
            this.JoystickCAPS = new JoystickAPI.JOYCAPS();

            //取得游戏手柄的参数信息
            if (JoystickAPI.joyGetDevCaps(joystickId, ref this.JoystickCAPS, Marshal.SizeOf(typeof(JoystickAPI.JOYCAPS)))
                == JoystickAPI.JOYERR_NOERROR)
            {
                this.IsConnected = true;
                this.Name = this.JoystickCAPS.szPname;
            }
            else
            {
                this.IsConnected = false;
            }

        }

        /// <summary>
        /// 返回当前游戏手柄的Id
        /// </summary>
        public int Id
        {
            get;
            private set;
        }

        /// <summary>
        /// 返回当前游戏手柄的名称
        /// </summary>
        public string Name
        {
            get;
            private set;
        }

        /// <summary>
        /// 返回当前游戏手柄是否已连接
        /// </summary>
        public bool IsConnected
        {
            get;
            private set;
        }

        /// <summary>
        /// 是否已捕捉
        /// </summary>
        private bool IsCapture
        {
            get;
            set;
        }

        /// <summary>
        /// 游戏手柄的参数信息
        /// </summary>
        private JoystickAPI.JOYCAPS JoystickCAPS;

        /// <summary>
        /// 定时器
        /// </summary>
        private Timer CaptureTimer;

        #region 事件定义
        /// <summary>
        /// 摇杆状态改变事件处理方法
        /// </summary>
        /// <param name="joyInfo">摇杆状态</param>
        public delegate void JoystickStateChangedHandler(JoystickState joyInfo);
        /// <summary>
        /// 摇杆状态改变事件
        /// </summary>
        public event JoystickStateChangedHandler JoystickStateChanged;
        /// <summary>
        /// 触发摇杆状态改变事件
        /// </summary>
        /// <param name="joyInfo">摇杆状态</param>
        protected void onJoystickStateChanged(JoystickState joyInfo)
        {
            if (JoystickStateChanged != null)
                JoystickStateChanged(joyInfo);
        }

        #endregion

        /// <summary>
        /// 捕捉游戏手柄
        /// </summary>
        /// <returns></returns>
        public void Capture()
        {
            if (this.IsConnected && !this.IsCapture)
            {
                //手柄已连接
                this.IsCapture = true;
                //this.CaptureTimer = new Timer(this.OnTimerCallback, null, 0, 50);
                this.CaptureTimer = new Timer(this.GetJoystickState, null, 0, 50);
            }
        }

        /// <summary>
        /// 释放捕捉
        /// </summary>
        public void ReleaseCapture()
        {
            if (this.IsCapture)
            {
                this.CaptureTimer.Dispose();
                this.CaptureTimer = null;
                this.IsCapture = false;
                this.IsConnected = false;
            }
        }

        JoystickAPI.JOYINFOEX _jsaPreviousJoystickState;
        /// <summary>
        /// 定时器的回调方法
        /// </summary>
        /// <param name="state">此参数无用</param>
        private void GetJoystickState(object state)
        {
            this.CaptureTimer.Change(Timeout.Infinite, Timeout.Infinite);

            JoystickState joyState = new JoystickState();
            JoystickAPI.JOYINFOEX infoEx = new JoystickAPI.JOYINFOEX()
            {
                dwSize = Marshal.SizeOf(typeof(JoystickAPI.JOYINFOEX)),
                dwFlags = (int)JoystickAPI.JOY_RETURNBUTTONS
            };

            int result = JoystickAPI.joyGetPosEx(this.Id, ref infoEx);
            if (result == JoystickAPI.JOYERR_NOERROR)
            {
                if (_jsaPreviousJoystickState != infoEx)
                {
                    List<byte> buttonList = GetButtonList(infoEx.dwButtons);
                    joyState.JoystickInfo = infoEx;
                    joyState.ButtonList = buttonList;
                    joyState.ID = this.Id;

                    _jsaPreviousJoystickState = infoEx;
                    this.onJoystickStateChanged(joyState);
                }
                this.CaptureTimer.Change(0, 50);
            }
            else
            {
                //其它值无法工作.则停止获取
                this.ReleaseCapture();
                JoystickState s = new JoystickState();
                s.ID = this.Id;
                s.ErrorCode = result;
                onJoystickStateChanged(s);
            }
        }

        private List<byte> GetButtonList(int dwButtons)
        {
            byte i = 1;
            List<byte> buttons = new List<byte>();

            while (dwButtons != 0)
            {
                if ((dwButtons & 0x01) != 0)
                    buttons.Add(i);
                dwButtons >>= 1;
                i++;
            }
            return buttons;
        }

        #region IDisposable 成员
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            this.ReleaseCapture();
            this.CaptureTimer = null;
        }

        #endregion
    }
}